<template>
  <div class="data-tables">
    <div class="data-tables-toolbar">
      <div class="data-tables-toolbar-left">
        <!--数据表头部左边工具栏-->
        <slot name="toolbarLeft"></slot>
        <template v-if="titles">
          <span class="data-tables-toolbar-left-title">{{ titles }}</span>
          <n-tooltip trigger="hover" v-if="titleTooltip">
            <template #trigger>
              <n-icon size="18">
                <QuestionCircleOutlined/>
              </n-icon>
            </template>
            {{ titleTooltip }}
          </n-tooltip>
        </template>
      </div>
      <div class="data-tables-toolbar-right">
        <div class="data-tables-toolbar-right-slot">
          <slot name="toolbarRight"></slot>
        </div>
        <n-divider vertical v-if="hasToolbarRight"/>
        <div class="data-tables-toolbar-right-icon">
          <n-tooltip trigger="hover" size="small">
            <template #trigger>
              <n-icon size="18" :class="{ rotation: clickReload }" @click="reloadData()">
                <Refresh/>
              </n-icon>
            </template>
            刷新
          </n-tooltip>
        </div>
        <div class="data-tables-toolbar-right-icon">
          <n-dropdown size="small" :show-arrow="true"
                      v-model:value="tableSize"
                      :options="tableDensityOption"
                      @select="densitySelect">
            <n-tooltip trigger="hover" size="small">
              <template #trigger>
                <n-icon size="18">
                  <ColumnHeightOutlined/>
                </n-icon>
              </template>
              密度
            </n-tooltip>
          </n-dropdown>
        </div>
        <div class="data-tables-toolbar-right-icon">
          <ColumnSetting/>
        </div>
      </div>
    </div>
    <div class="data-tables-content">
      <n-data-table ref="dataTableRef"
                    v-bind="getBindValues"
                    @update:page="updatePage"
                    @update:page-size="updatePageSize" :checked-row-keys="checkedRowDataKey"
                    @update:checked-row-keys="updateCheckedRowKeys">
        <template #empty>
          <n-empty :description="emptyText">
            <template #icon>
              <n-icon size="42">
                <BoxOpen/>
              </n-icon>
            </template>
          </n-empty>
        </template>
      </n-data-table>
    </div>
  </div>
</template>

<script lang="ts" setup>
import {customProps} from './props.ts';
import ColumnSetting from './components/ColumnSetting'
import {
  toRefs,
  computed,
  unref,
  ref,
  useSlots,
  onMounted,
  nextTick, watch, toRaw
} from 'vue';
import {ColumnHeightOutlined, QuestionCircleOutlined} from '@vicons/antd';
import {Refresh} from '@vicons/tabler'
import {BoxOpen} from '@vicons/fa';
import {ComponentRef} from '@/libs/help.ts';
import {getViewportOffset} from '@/util/domUtil.ts';
import {isBoolean} from '@/util/is.ts';
import {useWindowSizeFn} from '@/hooks/useWindowSizeFn.ts';
import {usePagination} from './hooks/usePagination.ts'
import {useLoading} from './hooks/useLoading.ts';
import {useDataSource} from './hooks/useDataSource.ts';
import {useColumns} from './hooks/useColumns.ts'
import {createTableContext} from './hooks/useTableContext.ts';

const props: any = defineProps(customProps);
let {titles, titleTooltip, emptyText} = toRefs(props);
//emits
const emits = defineEmits(['update:checked', 'fetch-success', 'fetch-error'])
//slot toolbarRight是否存在
const hasToolbarRight = !!useSlots().toolbarRight;
//点击刷新
const clickReload = ref(false);
//数据表ref
const dataTableRef = ref<ComponentRef>(null);
const wrapRef = ref<Nullable<HTMLDivElement>>(null);
//数据表数据
const tableData = ref<Recordable[]>([]);
//选中数据的key
const checkedRowDataKey = ref<any[]>([]);
//数据表高度
const deviceHeight = ref(500);
//数据表密度
const tableDensityOption = ref([
  {
    label: '默认',
    key: 'small'
  },
  {
    label: '中间',
    key: 'medium'
  },
  {
    label: '宽松',
    key: 'large'
  }
]);
//表格的尺寸
const tableSize = ref<string>(unref(props as any).size || "small");
//分页处理
const {getPaginationInfo, setPagination} = usePagination(props);
const paginationOption = computed(() => {
  return unref(getPaginationInfo);
});
//处理表头
const {
  setColumns,
  getColumns,
  getTableColumns,
  setCacheColumnsField,
  getCacheColumns
} = useColumns(props, {getPaginationInfo});

//分页参数
let paginationEl: HTMLElement | null;
//处理loading
const {getLoading, setLoading} = useLoading(props);
//数据处理
const {getDataSourceRef, reload} = useDataSource(
    props,
    {
      getPaginationInfo,
      setPagination,
      tableData,
      setLoading,
    },
    emits
);

//数据表绑定参数
const getBindValues = computed(() => {
  const tableData = unref(getDataSourceRef);
  const maxHeight = tableData.length ? `${unref(deviceHeight)}` : "auto";
  return {
    ...unref(props),
    loading: unref(getLoading),
    columns: unref(getTableColumns),
    data: tableData,
    rowKey: unref(props).rowKey,
    pagination: unref(getPaginationInfo),
    size: unref(tableSize),
    remote: true,
    "max-height": maxHeight,
  }
})

watch(() => unref(getDataSourceRef),
    (data) => {
      const {page} = unref(getPaginationInfo);
      const data_length = toRaw(data).length;
      if (data_length === 0 && page && page != 1) {
        const currentPage: number = page - 1;
        setPagination({page: currentPage});
        reload();
      }
    }
);

const tableAction = {
  reload,
  setColumns,
  setLoading,
  getColumns,
  getTableColumns,
  getDataSourceRef,
  getCacheColumns,
  setCacheColumnsField,
  emits
}
const getCanResize = computed(() => {
  const {canResize} = unref(props);
  return canResize;
});
const openRowKeys = (data: any, ids: any = []) => {
  for (let i = 0; i < data.length; i++) {
    if (data[i].children) {
      ids.push(data[i].id);
      openRowKeys(data[i].children, ids);
    }
  }
  return ids;
};

async function computeTableHeight() {
  const table = unref(dataTableRef);
  if (!table) return;
  if (!unref(getCanResize)) return;
  const tableEl: any = table?.$el;
  const headEl = tableEl.querySelector(".n-data-table-thead ");
  const {bottomIncludeBody} = getViewportOffset(headEl);
  const headerH = 64;
  let paginationH = 2;
  let marginH = 35;
  if (!isBoolean(paginationOption)) {
    paginationEl = tableEl.querySelector(".n-data-table__pagination") as HTMLElement;
    if (paginationEl) {
      const offsetHeight = paginationEl.offsetHeight;
      paginationH += offsetHeight || 0;
    } else {
      paginationH += 28;
    }
  }
  let height = bottomIncludeBody - (headerH + paginationH + marginH + (props.resizeHeightOffset || 0)) - 35;
  const maxHeight = props.maxHeight;
  height = maxHeight && maxHeight < height ? maxHeight : height;
  deviceHeight.value = height;
}

useWindowSizeFn(computeTableHeight, 280);
// @ts-ignore
createTableContext({...tableAction, wrapRef, getBindValues});
onMounted(() => {
  nextTick(() => {
    computeTableHeight();
  });
});
//选择数据表密度
const densitySelect = (e: string) => {
  tableSize.value = e;
};
//刷新当前数据表数据
const reloadData = () => {
  clickReload.value = true;
  setTimeout(() => {
    clickReload.value = false;
  }, 800);
  setPagination({page: 1});
  reload();
  cancelCheckData();
}
//跳转页码
const updatePage = (page: number) => {
  setPagination({page: page});
  reload();
}
//每页显示条数
const updatePageSize = (size: number) => {
  setPagination({page: 1, pageSize: size});
  reload();
}
//查询数据
const searchListData = () => {
  setPagination({page: 1});
  reload();
  cancelCheckData();
}
const updateCheckedRowKeys = (rowKeys: any) => {
  checkedRowDataKey.value = rowKeys;
  emits('update:checked', rowKeys)
}
const cancelCheckData = () => {
  checkedRowDataKey.value = [];
  emits("update:checked", checkedRowDataKey.value)
};
//子组件的方法在父组件调用
defineExpose({searchListData, reload, cancelCheckData})
</script>

<style scoped lang="scss">
.data-tables {
  &-toolbar {
    height: 32px;
    line-height: 32px;
    display: flex;
    justify-content: space-between;
    padding: 0 0 5px 0;

    &-left {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      flex: 1;

      &-title {
        padding-left: 5px;
        display: flex;
        align-items: center;
        justify-content: flex-start;
        font-size: 14px;
        font-weight: 600;
      }
    }

    &-right {
      display: flex;
      justify-content: flex-end;
      text-align: center;
      align-items: center;

      &-icon {
        display: flex;
        cursor: pointer;
        text-align: center;
        align-items: center;
        padding: 0 5px;
      }

      &-icon:hover {
        color: var(--primary-colors) !important;
      }

      .rotation {
        -webkit-animation-duration: 1s;
        animation-duration: 1s;
        -webkit-animation-timing-function: linear;
        animation-timing-function: linear;
        -webkit-animation-name: rotation;
        animation-name: rotation;
        -webkit-animation-iteration-count: infinite;
        animation-iteration-count: infinite;
        transform-origin: center;
      }

      @keyframes rotation {
        from {
          -webkit-transform: rotate3d(0, 0, 0.8, 360deg);
          transform: rotate3d(0, 0, 0.8, 360deg);
        }
        to {
          -webkit-transform: rotate3d(0, 0, 0.8, 0deg);
          transform: rotate3d(0, 0, 0.8, 0deg);
        }
      }
    }
  }
}
</style>